#define NOMINMAX
#include "AppMenuPanel.h"
#include "AppMenuCategoryPanel.h"
#include "AppMenuCommentsPanel.h"
#include  "../../IDefine.h"
#include "../CMD/CmdMgr.h"
#include <core/FileSys.h>
#include <core/Utility.h>
#include <QJsonDocument>
#include <QJsonValue>
#include <QJsonObject>
#include <QJsonArray>
#include <QStylePainter>
#include <QBoxLayout>
#include <QFile>
#include <QMouseEvent>
#include <QTimerEvent>
#include <QPainterPath>
#include <chrono>
#include "core/StyleMgr.h"
#include "core/ImageMgr.h"

using namespace std::chrono;

//TODO from configure
static constexpr int s_first_menu_height = /*40*/50;
static constexpr int s_first_menu_width = /*123*/150;
static constexpr int s_first_menu_space = 5;
static constexpr int s_first_menu_left_space = 9;
static constexpr int s_menu_logoHeight = 55;
static constexpr int s_max_favs = 9;

static system_clock::time_point s_timer_start = system_clock::time_point::max();
static QMap<int, system_clock::time_point> s_hover_times;

AppMenuPanel* AppMenuPanel::s_menu = nullptr;

static QRgb blendColorByTime(QRgb c1, QRgb c2, int elapsed, int max = 500)
{
	if (elapsed <= 0)
		return c1;
	if (elapsed > max)
		return c2;
	uint8_t alpha = (uint8_t)(elapsed * 255.0 / max);
	alpha = alpha <= 40 ? 40 : alpha;
	
	if (alpha == 255)	return c2;
	else if (alpha == 0)	return c1;

	int r = qRed(c1) + (((qRed(c2) - qRed(c1)) * alpha) >> 8);
	int g = qGreen(c1) + (((qGreen(c2) - qGreen(c1)) * alpha) >> 8);
	int b = qBlue(c1) + (((qBlue(c2) - qBlue(c1)) * alpha) >> 8);
	return qRgb(r, g, b);
}

AppMenuPanel::AppMenuPanel(QWidget* parent)
	: QFrame(parent),
	  m_imgLogo(nullptr),
	  m_imgLogoTitle(nullptr)

{
	m_imgLogo = ImgMgr::instance().image("guiframe_app_logo_title", WidgetStatus::kNormal, devicePixelRatioF());
	m_imgLogoTitle = ImgMgr::instance().image("guiframe_app_logo_title_text", WidgetStatus::kNormal, devicePixelRatioF());

	setWindowFlags(Qt::FramelessWindowHint | Qt::Popup);

	//use the stylesheet to draw border, will cause the panel pos changed when show comments panel!!
	//setStyleSheet("AppMenuPanel {border: 1px solid green; }");
	//setStyleSheet("border: 1px solid green;");
	setMouseTracking(true);
	setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);

	s_menu = this;
	construct();
	loadMenuComments();//do it in a thread?
}

void AppMenuPanel::onItemHoverChanged(int id, bool hovered)
{
	if (!hovered && m_commentsPanel->isVisible())
	{
		int width = size().width() - 228;
		m_commentsPanel->setVisible(false);
		setFixedWidth(width);
		resize(width, size().height());
	}
	else if (hovered && m_menuComments.contains(id))
	{
		int width = size().width();
		m_commentsPanel->setComments(m_menuComments[id]);
		m_commentsPanel->resize(228, size().height());
		bool isVisibleBefore = m_commentsPanel->isVisible();
		m_commentsPanel->setVisible(true);
		if (!isVisibleBefore)
		{
			setFixedWidth(width + 228);
			resize(width + 228, size().height());
		}
	}
}

void AppMenuPanel::onItemAction(int id, bool addToFav)
{
	if (m_FavPanel)
	{
		if (addToFav)
		{
			m_FavPanel->addCmd(id);
			CmdMgr::instance().addCommonPage(id);
		}
		else {
			m_FavPanel->removeCmd(id);
			CmdMgr::instance().removeCommonPage(id);
		}
	}
}

void AppMenuPanel::setFavPanel(AppMenuCategoryPanel* panel)
{
	m_FavPanel = panel;
	if (m_FavPanel) {
		for (auto it: CmdMgr::instance().commonPages())
		{
			m_FavPanel->addCmd(it);
		}
	}
}

bool AppMenuPanel::canAddToFav() const
{
	if (m_FavPanel)
		return m_FavPanel->cmdCount() < s_max_favs;

	return false;
}

bool AppMenuPanel::hasAddedToFav(int cmdId) const
{
	if (m_FavPanel)
		return m_FavPanel->hasCmd(cmdId);
	return false;
}

void AppMenuPanel::paintEvent(QPaintEvent* event)
{
	QStylePainter painter(this);
	QRect r = rect();

	//绘制背景色
	painter.fillRect(r, NAME_COLOR("MainTitleBack"));
	
	//绘制边框线
	QPen pen;
	pen.setWidth(1);
	pen.setColor(NAME_COLOR("Hover"));
	painter.setPen(pen);
	painter.setBrush(Qt::NoBrush);
	painter.drawRect(r);

	//绘制菜单logo、name、title
	QRect rc(s_first_menu_left_space, s_first_menu_left_space, s_first_menu_width, s_menu_logoHeight);
	int top = rc.top();
	rc.setRect(rc.left(), top, m_imgLogo->width(), m_imgLogo->height());
	painter.setRenderHint(QPainter::SmoothPixmapTransform);
	painter.drawImage(rc, *m_imgLogo);
	rc.setRect(rc.left()+rc.width()+6, top +(rc.height()-m_imgLogoTitle->height())/2, m_imgLogoTitle->width(), m_imgLogoTitle->height());
	painter.drawImage(rc, *m_imgLogoTitle);
	rc.setRect(rc.right()+7, top, m_imgLogo->width(), m_imgLogo->height());
	QFont font = painter.font();
	font.setPixelSize(12);
	painter.setFont(font);
	painter.setPen(QPen(NAME_COLOR("TextNormal")));
	painter.drawText(rc, tr("菜单"), QTextOption(Qt::AlignVCenter));

	//绘制菜单左侧分类
	for (int i=0; i<m_firstLabels.size(); i++){
		QRect rect = m_rects[i];
 		if (m_activeMenu == i){
			painter.fillRect(rect, QColor(23, 36, 34));
 		} else {
			if (i == m_hoverMenu){
				painter.fillRect(rect, QColor(25, 61, 55));
			} else if (m_timerAnimate == -1){
				//painter.fillRect(rect, /*QColor(23, 36, 34)*/NAME_COLOR("MainTitleBack"));
			} else {
				//鼠标滑动时，颜色淡化至背景色
				QColor c1(25, 61, 55);
				QColor c2 = NAME_COLOR("MainTitleBack");
				QColor c(blendColorByTime(c1.rgba(), c2.rgba(), duration_cast<milliseconds>(system_clock::now() - s_hover_times[i]).count()));
				painter.fillRect(rect, c);
			}
 		}

		rect.adjust(10, 0, 0, 0);
		font.setPixelSize(15);
		font.setBold(true);
		painter.setFont(font);
		painter.setPen(QPen(NAME_COLOR("Highlight")));
		painter.drawText(rect, Qt::AlignVCenter, m_firstLabels[i].second);

		if (i<m_redLabel.size() && m_redLabel[i].second) {
			qreal fTxtWidth = QFontMetrics(font).width(m_firstLabels[i].second);
			qreal fTxtHeight = QFontMetrics(font).height();
			painter.setPen(QColor(0xDF201F));
			painter.setBrush(QColor(0xDF201F));
			QPointF fPoint(rect.left()+fTxtWidth+5, rect.top()+(rect.height()-fTxtHeight)/2);
			painter.drawEllipse(fPoint, 2.0f, 2.0f);
		}
	}
}

void AppMenuPanel::mouseMoveEvent(QMouseEvent* e)
{
	//check which menu is the mouse on
	int hoverMenu = -1;
	QPoint pos = e->pos();
	for (int i = 0; i < m_rects.size(); i++)
	{
		if (m_rects[i].contains(pos))
		{
			hoverMenu = i;
			break;
		}
	}
	if (hoverMenu >=0 && hoverMenu < m_redLabel.size()) {
		if (m_redLabel[hoverMenu].second) {
			m_redLabel[hoverMenu].second = false;
			if (hoverMenu < m_categories.size())
			{
				QVector<AppMenuCategoryPanel*> panels = m_categories[hoverMenu];
				for (AppMenuCategoryPanel* panel : panels)
				{
					panel->removeRedPoint();
				}
			}
		}
	}

	//start timer to wait a while, if the mouse is still on it, switch menu
	if (hoverMenu != m_hoverMenu)
	{
		killSwitchTimer();
		if (m_hoverMenu != -1)
			s_hover_times[m_hoverMenu] = system_clock::now();
		m_hoverMenu = hoverMenu;
		if(m_hoverMenu != -1)
			m_timerSwitch = startTimer(500);
		if (m_timerAnimate == -1)
		{
			m_timerAnimate = startTimer(40);
			s_timer_start = system_clock::now();
		}
		update();
	}
}

void AppMenuPanel::timerEvent(QTimerEvent* e)
{
	if (e->timerId() == m_timerSwitch)
	{
		killAnimateTimer();
		killSwitchTimer();
		switchMenu(m_hoverMenu);
	}
	else if (e->timerId() == m_timerAnimate)
	{
		auto elapsed = duration_cast<milliseconds>(system_clock::now() - s_timer_start);
		if (elapsed.count() > 1000) //1second
		{
			killAnimateTimer();
		}
		update();
	}
}

void AppMenuPanel::loadMenuComments()
{
	QJsonDocument doc = CoreUtility::openJsonDoc(FileSys::instance()->appCfgDir() + "/menuComment.json");
	if (doc.isNull())
	{
		logError(MODULE_NAME, "Open qb menuComment config file failed!"); 
		return;
	}
	QJsonArray comments = doc.array();

	QJsonValue comment;
	foreach(comment, comments)
	{
		QJsonObject obj = comment.toObject();
		int id = obj["id"].toInt();
		
		MenuComments mc;
		mc.title = obj["title"].toString();

		QJsonArray commentList = obj["comment"].toArray();
		QJsonValue var;
		foreach(var, commentList)
		{
			QJsonObject varObj = var.toObject();
			QString text = varObj["text"].toString();
			QString colorStr = varObj["color"].toString();
			QColor color(colorStr.toInt(nullptr, 16));
			mc.comments.push_back({ text, color });
		}

		m_menuComments[id] = mc;
	}
}

void AppMenuPanel::onCommonPage(int* ids, int size, int ntype)
{
	//do commonpage
	switch (ntype)
	{
	case 0:
		CmdMgr::instance().setCommonPages(ids, size);
		break;
	default:
		break;
	}
}

void AppMenuPanel::construct()
{
	if (m_mainLayout) {
		switchMenu(-1);
	} else {
		m_mainLayout = new QHBoxLayout();
		m_mainLayout->setContentsMargins(0, 0, 0, 0);
		m_mainLayout->setSpacing(0);
		m_mainLayout->addSpacing(s_first_menu_width + s_first_menu_left_space + 10);
	}

	QJsonDocument doc = CoreUtility::openJsonDoc(FileSys::instance()->appCfgDir() + "/menu.json");
	if (doc.isNull())
	{
		logError(MODULE_NAME, "Open menu configure failed!");
		return;
	}

	int x = s_first_menu_left_space + 1;//1:border
	int y = s_first_menu_space + s_menu_logoHeight;

	int index = 0;
	QJsonArray menuObj = doc.array();
	if (m_categories.size() > 0) {
		m_categories.clear();
	}
	m_rects.clear();
	m_categories.resize(menuObj.size());

	if (m_firstLabels.size() > 0) {
		m_firstLabels.clear();
	}

	QJsonValue var;
	foreach(var, menuObj)
	{
		//first level
		QJsonObject obj = var.toObject();
		//second level:
		QJsonArray menuCateogries = obj["submenu"].toArray();
		for (QJsonValue categoryObj : menuCateogries)
		{
			QJsonObject obj = categoryObj.toObject();
			AppMenuCategoryPanel* categoryPanel = new AppMenuCategoryPanel(&obj, this);
			if (categoryPanel->cmdCount() == 0 && !categoryPanel->isFavePanel()) {
				categoryPanel->deleteLater();
				continue;
			}
			categoryPanel->setVisible(false);
			m_categories[index].push_back(categoryPanel);
		}
		if (m_categories[index].size() == 0) {
			continue;
		}

		int id = obj["id"].toInt();
		QString title = obj["title"].toString();
		m_firstLabels.push_back({ id, title });

		QRect rect(x, y, s_first_menu_width, s_first_menu_height);
		m_rects.push_back(rect);
		y += s_first_menu_height;

		s_hover_times[index] = system_clock::now();
		++index;
	}

	if (!m_commentsPanel) {
		m_commentsPanel = new AppMenuCommentsPanel(this);
		m_commentsPanel->setVisible(false);
	}

	setLayout(m_mainLayout);
	initRedPointLabel();
	switchMenu(0);
}

void AppMenuPanel::switchMenu(int index)
{
	//remove old widgets and set unvisible
	if(m_commentsPanel){
		m_commentsPanel->setVisible(false);
	}
	if (m_activeMenu != -1)
	{
		QVector<AppMenuCategoryPanel*> panels = m_categories[m_activeMenu];
		for(AppMenuCategoryPanel* panel : panels)
		{
			panel->setVisible(false);
			m_mainLayout->removeWidget(panel);
		}
	}
	m_mainLayout->removeWidget(m_commentsPanel);

	m_activeMenu = index;
	
	int menuWidth = s_first_menu_width + s_first_menu_left_space + 10;
	if (m_activeMenu != -1)
	{
		QVector<AppMenuCategoryPanel*> panels = m_categories[m_activeMenu];
		for(AppMenuCategoryPanel* panel : panels)
		{
			panel->setVisible(true);
			m_mainLayout->addWidget(panel);
		}
		menuWidth += 170 * panels.size();
	}

	m_mainLayout->addWidget(m_commentsPanel);
	setFixedWidth(menuWidth);
	resize(menuWidth, std::max(m_rects.last().bottom() + 10, m_mainLayout->sizeHint().height()));

	update();
}

void AppMenuPanel::initRedPointLabel()
{
	m_redLabel.clear();

	int nIndex = 0;
	for (auto it : m_categories)
	{
		bool bRedPoint = false;
		for (auto itSub : it)
		{
			if (itSub && itSub->isRedPoint()) {
				bRedPoint = true;
				break;
			}
		}
		m_redLabel.push_back({ nIndex, bRedPoint });
		++nIndex;
	}
}

void AppMenuPanel::killAnimateTimer()
{
	if (m_timerAnimate == -1)
		return;

	killTimer(m_timerAnimate);
	m_timerAnimate = -1;
}

void AppMenuPanel::killSwitchTimer()
{
	if (m_timerSwitch == -1)
		return;

	killTimer(m_timerSwitch);
	m_timerSwitch = -1;
}
